package com.canaan.business.service.basic.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.stream.Collectors;

import cn.hutool.core.collection.CollectionUtil;
import com.canaan.business.common.enums.basic.ContainerStatusEnum;
import com.canaan.business.common.enums.basic.ContainerTypeEnum;
import com.canaan.business.domain.basic.Container;
import com.canaan.business.domain.basic.ContainerBarcode;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.BarcodeVo;
import com.canaan.business.mapper.basic.ContainerBarcodeMapper;
import com.canaan.business.service.basic.IContainerBarcodeService;
import com.canaan.business.service.basic.IContainerService;
import com.canaan.business.service.storehouse.IWmsBarcodeRecordService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import org.apache.commons.compress.utils.Lists;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

/**
 * WMS 容器绑定条码Service业务层处理
 *
 * @author ruoyi
 * @date 2023-08-01
 */
@Service
public class ContainerBarcodeServiceImpl implements IContainerBarcodeService {
    @Resource
    private ContainerBarcodeMapper containerBarcodeMapper;
    @Resource
    IWmsBarcodeRecordService wmsBarcodeRecordService;

    @Resource
    private IContainerService containerService;
    @Resource
    private IWmsStorehouseStockService wmsStorehouseStockService;

    /**
     * 查询WMS 容器绑定条码
     *
     * @param id WMS 容器绑定条码主键
     * @return WMS 容器绑定条码
     */
    @Override
    public ContainerBarcode selectContainerBarcodeById(Long id) {
        return containerBarcodeMapper.selectContainerBarcodeById(id);
    }

    /**
     * 查询WMS 容器绑定条码列表
     *
     * @param containerBarcode WMS 容器绑定条码
     * @return WMS 容器绑定条码
     */
    @Override
    public List<ContainerBarcode> selectContainerBarcodeList(ContainerBarcode containerBarcode) {
        return containerBarcodeMapper.selectContainerBarcodeList(containerBarcode);
    }

    /**
     * 新增WMS 容器绑定条码
     *
     * @param containerBarcode WMS 容器绑定条码
     * @return 结果
     */
    @Override
    public int insertContainerBarcode(ContainerBarcode containerBarcode) {
        containerBarcode.setCreateBy(SecurityUtils.getUsername());
        containerBarcode.setCreateTime(DateUtils.getNowDate());
        return containerBarcodeMapper.insertContainerBarcode(containerBarcode);
    }

    /**
     * 批量新增WMS 容器绑定条码
     *
     * @param containerBarcodeList WMS 容器绑定条码列表
     * @return 结果
     */
    @Override
    public int batchInsertContainerBarcode(List<ContainerBarcode> containerBarcodeList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (ContainerBarcode containerBarcode : containerBarcodeList){
            containerBarcode.setCreateBy(username);
            containerBarcode.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<containerBarcodeList.size();) {
            int endIndex = i+500;
            if (endIndex > containerBarcodeList.size()) {
                endIndex = containerBarcodeList.size();
            }
            insertNum = insertNum + containerBarcodeMapper.batchInsertContainerBarcode(containerBarcodeList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改WMS 容器绑定条码
     *
     * @param containerBarcode WMS 容器绑定条码
     * @return 结果
     */
    @Override
    public int updateContainerBarcode(ContainerBarcode containerBarcode) {
        containerBarcode.setUpdateBy(SecurityUtils.getUsername());
        containerBarcode.setUpdateTime(DateUtils.getNowDate());
        return containerBarcodeMapper.updateContainerBarcode(containerBarcode);
    }

    /**
     * 批量修改WMS 容器绑定条码
     *
     * @param containerBarcodeList WMS 容器绑定条码列表
     * @return 结果
     */
    @Override
    public int batchUpdateContainerBarcode(List<ContainerBarcode> containerBarcodeList) {
        if (CollectionUtil.isEmpty(containerBarcodeList)){
            throw new ServiceException("数据不能为空");
        }
        // 校验是否只有一个容器编号
        List<String> containerNos = containerBarcodeList.stream().map(ContainerBarcode::getContainerNo).distinct().collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(containerNos) && containerNos.size() > 1){
            throw new ServiceException("一次绑定不允许出现多个容器编号，请修改后提交");
        }
        // 校验所有条码是否都未绑定其他容器
        List<String> barcodes = containerBarcodeList.stream().map(ContainerBarcode::getBarcode).collect(Collectors.toList());
        ContainerBarcode searchParam = new ContainerBarcode();
        searchParam.setContainerNo(containerBarcodeList.get(0).getContainerNo());
        searchParam.setBarcodeList(barcodes);
        List<ContainerBarcode> relBarcodeInfoList = this.containerBarcodeMapper.selectBarcodeRelInfo(searchParam);
        if (CollectionUtil.isNotEmpty(relBarcodeInfoList)){
            throw new ServiceException("条码[" + relBarcodeInfoList.get(0).getBarcode() + "]已关联编号为[" + relBarcodeInfoList.get(0).getContainerNo() + "]的容器，请修改后提交");
        }
        // 删除旧的绑定关系数据
        this.containerBarcodeMapper.deleteContainerBarcodeByContainerNo(containerBarcodeList.get(0).getContainerNo());

        // 新增新的绑定关系数据
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (ContainerBarcode containerBarcode : containerBarcodeList){
            containerBarcode.setUpdateBy(username);
            containerBarcode.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<containerBarcodeList.size();) {
            int endIndex = i+500;
            if (endIndex > containerBarcodeList.size()) {
                endIndex = containerBarcodeList.size();
            }
            updateNum = updateNum + containerBarcodeMapper.batchInsertContainerBarcode(containerBarcodeList.subList(i, endIndex));
            i = endIndex;
        }

        // 修改容器状态
        Container container = this.containerService.selectContainerByNo(containerBarcodeList.get(0).getContainerNo());
        container.setStatus(ContainerStatusEnum.USE.getCode());
        this.containerService.updateContainer(container);
        return updateNum;
    }

    /**
     * 批量删除WMS 容器绑定条码
     *
     * @param ids 需要删除的WMS 容器绑定条码主键集合
     * @return 结果
     */
    @Override
    public int deleteContainerBarcodeByIds(Long[] ids) {
        int delNum = 0;
        // 循环判断删除后是否需要修改容器状态
        for (Long id : ids) {
            ContainerBarcode containerBarcode = this.selectContainerBarcodeById(id);
            delNum += this.containerBarcodeMapper.deleteContainerBarcodeById(id);
            // 修改容器状态
            Container container = this.containerService.selectContainerByNo(containerBarcode.getContainerNo());
            if (CollectionUtil.isEmpty(container.getContainerBarcodeList())){
                container.setStatus(ContainerStatusEnum.FREE.getCode());
                this.containerService.updateContainer(container);
            }
            // 更新库存容器
            wmsStorehouseStockService.updateContainerByBarcode(containerBarcode.getBarcode());
        }
        return delNum;
    }

    /**
     * 删除WMS 容器绑定条码信息
     *
     * @param id WMS 容器绑定条码主键
     * @return 结果
     */
    @Override
    public int deleteContainerBarcodeById(Long id) {
        ContainerBarcode containerBarcode = this.selectContainerBarcodeById(id);
        // 修改容器状态
        Container container = this.containerService.selectContainerByNo(containerBarcode.getContainerNo());
        if (CollectionUtil.isEmpty(container.getContainerBarcodeList())){
            container.setStatus(ContainerStatusEnum.FREE.getCode());
            this.containerService.updateContainer(container);
        }

        return containerBarcodeMapper.deleteContainerBarcodeById(id);
    }

    /**
     * 根据容器编号查询
     * @param containerNo
     * @return
     */
    @Override
    public List<ContainerBarcode> selectByContainerNo(String containerNo) {
        ContainerBarcode query = new ContainerBarcode();
        query.setContainerNo(containerNo);
        return this.containerBarcodeMapper.selectContainerBarcodeList(query);
    }

    /**
     * 根据容器编码查询入库条码信息
     * @param containerNo
     * @return
     */
    @Override
    public List<BarcodeVo> selectInStockBarCodeByContainerNo(String containerNo) {
        List<BarcodeVo> barcodeVoList = Lists.newArrayList();
        Container container = this.containerService.selectContainerByNo(containerNo);
        if (container==null){
            throw new ServiceException(containerNo+"：该容器不存在");
        }else{
                if (ContainerStatusEnum.IN_STOCK.equals(container.getStatus())){
                    throw new ServiceException("该容器已入库,不允许重复入库");
                }else{
                    container.setStatus(ContainerStatusEnum.IN_STOCK.getCode());
                }
        }
        List<ContainerBarcode> containerBarcodeList = this.selectByContainerNo(containerNo);
        if (CollectionUtil.isEmpty(containerBarcodeList)){
            throw new ServiceException(containerNo+"：容器未绑定条码");
        }
        BarcodeVo barcodeVo ;
        for (ContainerBarcode containerBarcode : containerBarcodeList){
            barcodeVo = this.wmsBarcodeRecordService.getInStockBarcodeInfo(containerBarcode.getBarcode(),containerNo,1);
            if (barcodeVo ==null){
                barcodeVo = new BarcodeVo();
            }
            barcodeVo.setContainerNo(containerNo);
            barcodeVo.setContainerType(ContainerTypeEnum.getMessageByCode(container.getContainerType()));
            barcodeVoList.add(barcodeVo);
        }
        return barcodeVoList;
    }


    /**
     * 根据容器编号或条码号查询容器信息
     * @param containerNoOrBarcode 容器编号或条码编号
     * @return Container
     */
    @Override
    public List<Container> selectByContainerNoOrBarcode(String containerNoOrBarcode){
        List<String> noListWithoutDuplicates = new ArrayList<>();
        Container searchContainer = new Container();
        searchContainer.setNo(containerNoOrBarcode);
        // 用容器编号查询
        List<Container> containerList = this.containerService.selectContainerList(searchContainer);
        List<String> containerNos = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(containerList)){
            containerNos = containerList.stream().map(Container::getNo).collect(Collectors.toList());
        }
        // 根据条码查询
        ContainerBarcode query = new ContainerBarcode();
        query.setBarcode(containerNoOrBarcode);
        List<ContainerBarcode> barcodeList = this.containerBarcodeMapper.selectContainerBarcodeList(query);
        if (CollectionUtil.isNotEmpty(barcodeList)){
            // 将所有容器编号组合
            containerNos.addAll(barcodeList.stream().map(ContainerBarcode::getContainerNo).collect(Collectors.toList()));
            // 去重
            noListWithoutDuplicates = new ArrayList<>(new HashSet<>(containerNos));
        }
        if (CollectionUtil.isNotEmpty(noListWithoutDuplicates)){
            Container searchContainerNos = new Container();
            searchContainerNos.setNos(noListWithoutDuplicates);
            containerList = this.containerService.selectContainerList(searchContainerNos);
        }
        return containerList;
    }

    /**
     * 根据容器编码查询出库的库存条码信息
     * @param containerNo
     * @return
     */
    @Override
    public List<WmsStorehouseStock> selectOutStockBarCodeByContainerNo(String containerNo) {
        List<WmsStorehouseStock> storehouseStockList = Lists.newArrayList();
        Container container = this.containerService.selectContainerByNo(containerNo);
        if (container==null){
            throw new ServiceException(containerNo+"：该容器不存在");
        }else {
            if (!ContainerStatusEnum.IN_STOCK.getCode().equals(container.getStatus())){
                throw new ServiceException("该容器未入库,不允许出库");
            }else{
                container.setStatus(ContainerStatusEnum.FREE.getCode());
            }
        }
        List<ContainerBarcode> containerBarcodeList = this.selectByContainerNo(containerNo);
        if (CollectionUtil.isEmpty(containerBarcodeList)){
            throw new ServiceException(containerNo+"：容器未绑定条码");
        }
        WmsStorehouseStock storehouseStock ;
        for (ContainerBarcode containerBarcode : containerBarcodeList){
            storehouseStock = this.wmsStorehouseStockService.getInfoByBarcode(containerBarcode.getBarcode());
            if (storehouseStock ==null){
                storehouseStock = new WmsStorehouseStock();
            }
            storehouseStock.setContainerNo(containerNo);
            storehouseStock.setContainerType(ContainerTypeEnum.getMessageByCode(container.getContainerType()));
            storehouseStockList.add(storehouseStock);
        }
        return storehouseStockList;
    }

    /**
     * 根据条码查询
     * @param barcode
     * @return
     */
    @Override
    public List<ContainerBarcode> selectByBarcode(String barcode) {
        ContainerBarcode query = new ContainerBarcode();
        query.setBarcode(barcode);
        List<ContainerBarcode> list = this.containerBarcodeMapper.selectContainerBarcodeList(query);
        return list;
    }

    /**
     * 根据条码查询
     * @param barcode
     * @return
     */
    @Override
    public ContainerBarcode getByBarcode(String barcode) {
        List<ContainerBarcode> list = selectByBarcode(barcode);
        if (CollectionUtil.isNotEmpty(list)){
            return list.get(0);
        }
        return null;
    }

}
